#include "pkg_freebsd.h"
#include "pkg.h"

#include <stdio.h>
#include <string.h>

#define EXTENSION       ".tbz"
#define TEMP_EXTENSION  ".pkg_install-XXXXXX"

#define DL_BUFFER_SIZE  8192

/* 
 * Download a package to a specific location "dest".
 *
 * Returns:
 * 0 - complete with no detected issues
 * 1 - completed with possible issues
 * -1 - failure
 */
int
pkg_freebsd_download_package(const char *pkgname, const char *local)
{
        struct pkg_repo repo;
        FILE *fetch;
        int fd;
        char *repoloc;
        char archive_name[PATH_MAX];
        char remote_name[PATH_MAX];
        char temp_name[PATH_MAX];
        char dest_name[PATH_MAX];
        size_t remote_size;
        int r;
        int w;
        int total_down;
        int buffer[DL_BUFFER_SIZE];
        int ret;
         
        if (dest == NULL) {
                /* For now, atleast, force a destination. */
                return (-1);
        }

        /* XXX: Gather information about repository locations and repository
         * directories. */
        repoloc = NULL;
        
        /* Initialize a FreeBSD stype ftp repository. */
        pkg_repo_init(&repo, FREEBSD_FTP);
        
        /* Open the repository. */
        if (repo.open(repo, repoloc, 0) != PKG_OK) {
                warn("Warning: couldn't open repository at %s", repoloc);
                return (-1);
        }

        strcpy(finalname, pkgname);
        strcat(finalname, EXTENSION);

        fetch = repo.fetch(repo, archive_name, remote_name, &remote_size, 0);
        if (fetch == NULL) {
#if BUILD_COMPATIBLE
                /* XXX: This isn't actually correct. */
                fprintf(stderr, "Error: Unable to get %s: File unavailable "
                        "(e.g., file not found, no access)\n", remote_name);
#endif
                return (-1);
        }

#if BUILD_COMPATIBLE
        printf("Fetching %s... ", remote_name);
        fflush(stdout);
#endif   

        /* Breaks 'resume-download', I guess... Think about it... */
        strcpy(temp_name, dest);
        strcpy(temp_name, TEMP_EXTENSION);
        fd = open(temp_name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (fd < 0) {
                warn("Could not open local destination (%s).", temp_name);
                return (-1);
        }
        
        total_down = 0;
        while ((r = fread(buffer, 1, sizeof(buffer), fetch)) > 0) {
                if ((w = write(fd, buffer, r)) != r) {
                        warn("Warning: short write().");
                        break;
                }
                /* We can do dl speed/completion tracking with this... */
                total_down += w;
                /* something->callback(total_down, remote_size); */
        }

        ret = 0;
        if (ferror(fetch)) {
#if BUILD_COMPATIBLE
                warn("warning: error reading from server");
#endif
                ret = -1;
        }
        
        fclose(fetch);
        close(fd);

        if (ret == -1) {
                /* We're not really sure what we've got on disk... */
                unlink(temp_name);
        } else if (ret == 0) {
#if BUILD_COMPATIBLE
                printf("Done.\n");
#endif
                if (stat(temp_name, &sb) < 0) {
                        warnx("Warning: can't stat() downloaded package.");
                        ret = 1;
                } else if (sb.st_size != remote_size) {
                        /* Size mismatch. */
                        warn("Warning: remote size does not match local size.");
                        ret = 1;
                }
                /* Now, rename the temp file into dest. */
                if (rename(temp_name, dest_name) < 0) {
                        /* 
                         * Rename failed, delete the temp.  I should probably
                         * add a flag to stop this from happening if the client
                         * want's the temps. 
                         */
                        warnx("Warning: rename failed.");
                        unlink(temp_name);
                        ret = -1;
                }
        }

        return (ret);
}
